package com.tomorrow.runner.service;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Build;

import com.tomorrow.runner.util.AndroidBuild;
import com.tomorrow.runner.util.SensorUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * 步伐检测器
 * Created by tomorrow on 16-5-1.
 */
public class StepsDetector {

    public interface OnStepDetectListener {
        int FACE_UP = 1;
        int FACE_DOWN = 2;
        int SIDE_LEFT = 3;
        int SIDE_RIGHT = 4;
        int STAND_UP = 5;
        int STAND_DOWN = 6;
        void onDetectOrientation(int orientation);
        void onDetect(StepsDetector detector,float threshold);
        void onMissDetect(StepsDetector detector,float threshold);
    }

    public static final long DEFAULT_PERIOD = 600;
    public static final float DEFAULT_THRESHOLD = 1.0f;
    private long lastTimestamp = System.currentTimeMillis();
    private long mPeriod = DEFAULT_PERIOD;//ms  一步大约需要600ms 取1/4
    private List<Float> mThresholdList;
    private float pG = SensorManager.STANDARD_GRAVITY;
    private  double maxG = SensorManager.STANDARD_GRAVITY;
    private double minG = SensorManager.STANDARD_GRAVITY;
    private OnStepDetectListener mListener;
    private SensorManager manager;

    public void setListener(OnStepDetectListener listener) {
        this.mListener = listener;
    }
    public StepsDetector(Context context,OnStepDetectListener listener){
        if (!SensorUtil.isSupportSensor(context, Sensor.TYPE_ACCELEROMETER)){
            throw  new IllegalStateException("you device do not support ACCELEROMETER sensor");
        }
        manager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        mThresholdList = new ArrayList<>();
        this.mListener = listener;
        mThresholdList.add(DEFAULT_THRESHOLD);
    }
    public void addThreshold(float threshold){
        if (mThresholdList.contains(threshold)){
            return;
        }
        mThresholdList.add(threshold);
    }

    public boolean startDetect(){
        if (mListener == null){
            throw new IllegalStateException("you should set an OnStepDetectListener before detect");
        }
        Sensor sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (AndroidBuild.isGreatThanOrEqualSdk(Build.VERSION_CODES.KITKAT)){
            return manager.registerListener(sensorEventListener,sensor,SensorManager.SENSOR_DELAY_NORMAL,1000);
        }
        else{
            return manager.registerListener(sensorListener,Sensor.TYPE_ACCELEROMETER,SensorManager.SENSOR_DELAY_NORMAL);
        }
    }

    public void stopDetect(){
        if (AndroidBuild.isGreatThanOrEqualSdk(Build.VERSION_CODES.KITKAT)){
            manager.unregisterListener(sensorEventListener);
        }
        else{
            manager.unregisterListener(sensorListener);
        }
    }
    private void detectSteps(float xAixs , float yAixs, float zAixs){
        //变为绝对值
        float x = Math.abs(xAixs);
        float y = Math.abs(yAixs);
        float z = Math.abs(zAixs);
        //判断手机重力方向
        float max = getMax(x,y,z);
        float G = 0;
        if (max ==x){
            //手机侧立
            G = x;
            mListener.onDetectOrientation(xAixs > 0 ? OnStepDetectListener.SIDE_RIGHT:OnStepDetectListener.SIDE_LEFT);
        }
        if (max == y){
            //手机正立
            G = y;
            mListener.onDetectOrientation(yAixs > 0 ? OnStepDetectListener.STAND_UP:OnStepDetectListener.STAND_DOWN);
        }
        if (max == z){
            //手机平放
            G = z;
            mListener.onDetectOrientation(zAixs > 0 ? OnStepDetectListener.FACE_UP:OnStepDetectListener.FACE_DOWN);
        }
        //检查时间
        long period = System.currentTimeMillis() - lastTimestamp;
        if(period > mPeriod ){
            //可以检测
            for(float threshold : mThresholdList){
                if (_detect(threshold)){
                    mListener.onDetect(this,threshold);
                }
                else{
                    mListener.onMissDetect(this,threshold);
                }
            }
            //重置
            lastTimestamp = System.currentTimeMillis();
            maxG = SensorManager.STANDARD_GRAVITY;
            minG = SensorManager.STANDARD_GRAVITY;
        }else{
            //上一点大于现在,正在下降
            if (pG > G){
                //记录下降的最低点
                if (G <= minG){
                    minG = G;
                }
                else{
                    //越过了波谷，将要上升
                    pG = G;
                }
            }
            else{//正在上升
                //记录上升的最高点
                if (G >= maxG){
                    maxG = G;
                }
                else{
                    //越过了波峰，将要下降
                    pG = G;
                }
            }
        }
    }
    private boolean _detect(float threshold) {
        if (maxG  >= (threshold + SensorManager.STANDARD_GRAVITY)){
            if (minG <= (SensorManager.STANDARD_GRAVITY - threshold)){
                return true;
            }
        }
        return false;
    }

    private float getMax(float x, float y, float z) {
        float max = x;
        if (max < y){
            max = y;
        }
        if (max <z){
            max = z;
        }
        return max;
    }

    public long getPeriod() {
        return mPeriod;
    }

    public void setPeriod(long period) {
        this.mPeriod = period;
    }
    //SDK >= KITKAT
    private SensorEventListener sensorEventListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            detectSteps(event.values[0],event.values[1],event.values[2]);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {

        }
    };
    //SDK < KITKAT
    private SensorListener sensorListener = new SensorListener() {
        @Override
        public void onSensorChanged(int sensor, float[] values) {
            detectSteps(values[0],values[1],values[2]);
        }

        @Override
        public void onAccuracyChanged(int sensor, int accuracy) {

        }
    };
}
